# 函数

# 内置函数
print(abs(100))
print(abs(-20))
print(max(1, 2, -1, -4))
print(str(123))
print(bool(1))
print(bool(0))
print(bool(""))
a = abs  # 函数名其实就是指向一个函数对象的引用，完全可以把函数名赋给一个变量，相当于给这个函数起了一个“别名”：
print(a(-10))


# 自定义函数
def my_abs(x):
    # 当传入了不恰当的参数时，内置函数abs会检查出参数错误，
    # 数据类型检查可以用内置函数isinstance()实现：
    if not isinstance(x, (int, float)):
        raise TypeError('bad operand type')
    if x >= 0:
        return x
    else:
        return -x


print(my_abs(-11))


# 空函数,如果想定义一个什么事也不做的空函数，可以用pass语句
def nop():
    pass


# pass语句什么都不做，那有什么用？实际上pass可以用来作为占位符，比如现在还没想好怎么写函数的代码，就可以先放一个pass，让代码能运行起来。
# pass还可以用在其他语句里，比如：
# if 1 >= 18:
#     pass
# 缺少了pass，代码运行就会有语法错误。

# 函数的参数
# 默认参数
def power(x, n=2):
    s = 1
    while n > 0:
        n -= 1
        s *= x
    return s


print(power(3))
print(power(3, 3))
print(pow(3, 4))


# 可变参数
def calc(*nums):
    sum = 0
    for n in nums:
        sum += n * n
    return sum


print(calc())
print(calc(1))
print(calc(1, 2))
print(calc(1, 2, 3))
print(calc(1, 2, 3, 4))


# 关键字参数
# 可变参数允许你传入0个或任意个参数，这些可变参数在函数调用时自动组装为一个tuple。
# 而关键字参数允许你传入0个或任意个含参数名的参数，这些关键字参数在函数内部自动组装为一个dict。
def person(name, age, **kw):
    if 'city' in kw:
        print('city=', kw['city'])
    print('name:', name, 'age:', age, 'other:', kw)


person('ljy', 18)
person('ljy', 28, city='beijing')
person('ljy', 38, city='beijing', job='coder')
extra = {'city': 'bj', 'job': 'coder'}
person('ljy', 48, **extra)


# 命名关键字参数
# 命名关键字参数需要一个特殊分隔符*，*后面的参数被视为命名关键字参数。
def person2(name, age, *, city, job):
    print('name:', name, 'age:', age, 'other:', city, job)


person2('ljy', 58, city='beijing', job='coder')


def person3(name, age, *, city='bj', job='coder'):
    print('name:', name, 'age:', age, 'other:', city, job)


person3('ljy', 68, job='super coder')


# 参数组合
# 可以用必选参数、默认参数、可变参数、关键字参数和命名关键字参数，这5种参数都可以组合使用。
# 但是请注意，参数定义的顺序必须是：必选参数、默认参数、可变参数、命名关键字参数和关键字参数。
def f1(a, b, c=0, *args, **kw):
    print('a =', a, 'b =', b, 'c =', c, 'args =', args, 'kw =', kw)


def f2(a, b, c=0, *, d, **kw):
    print('a =', a, 'b =', b, 'c =', c, 'd =', d, 'kw =', kw)


f1(1, 2)
f1(1, 2, c=3)
f1(1, 2, 3, 'a', 'b')
f1(1, 2, 3, 'a', 'b', x=99)
f2(1, 2, d=99, ext=None)

args = (1, 2, 3, 4)
kw = {'d': 99, 'x': '#'}
f1(*args, **kw)
args = (1, 2, 3)
kw = {'d': 88, 'x': '#'}
f2(*args, **kw)


# 递归函数
# 在函数内部，可以调用其他函数。如果一个函数在内部调用自身本身，这个函数就是递归函数
def fact(n):
    if n == 1:
        return 1
    return n * fact(n - 1)


print(fact(1))
print(fact(2))
print(fact(3))
print(fact(4))
